#pragma once

#include"err.hpp"
#include<iostream>
#include<functional>
#include<string>
#include<cerrno>
#include<cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

namespace ns_server
{
    //执行方法
    using func_t=std::function<std::string (std::string)>;

    class UdpServer
    {
    public:
        //构造函数获取端口号和IP地址
        UdpServer(uint16_t port,func_t func):_port(port),_func(func)
        {}

        //初始化服务器
        void InitServer()
        {
            _sock=socket(AF_INET,SOCK_DGRAM,0);
            if(_sock<0)
            {
                std::cerr<<"create sock error,"<<strerror(errno)<<std::endl;
                exit(SOCKET_ERR);
            }
            std::cout << "create socket success: " << _sock << std::endl;

            struct sockaddr_in local;
            bzero(&local,sizeof(local));//清空结构体

            local.sin_family=AF_INET;//地址类型
            local.sin_port=htons(_port);//端口号
            local.sin_addr.s_addr=INADDR_ANY;

            //绑定结构体
            if(bind(_sock,(struct sockaddr*)&local,sizeof(local))<0)
            {
                std::cerr<<"bind error,"<<strerror(errno)<<std::endl;
                exit(BIND_ERR);
            }
            std::cout << "bind socket success: " << _sock << std::endl;
        }
        //启动服务器
        void Start()
        {
            char buffer[1024];
            while(true)
            {
                struct sockaddr_in client;
                memset(&client,0,sizeof(client));
                socklen_t len=sizeof(client);
                //socklen_t len=0;

                //缓冲区需要预留\0的位置
                int n=recvfrom(_sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&client,&len);
                if(n>0) buffer[n]='\0';
                else continue;

                //提取客户端信息
                std::string clientIp=inet_ntoa(client.sin_addr);
                uint16_t clientPort=ntohs(client.sin_port);

                std::cout<<"["<<clientIp<<" : "<<clientPort<<"]# "<<buffer<<std::endl;

                //处理函数
                std::string responce = _func(buffer);

                //送回数据
                sendto(_sock,responce.c_str(),responce.size(),0,(struct sockaddr*)&client,sizeof(client));
            }
        }
        ~UdpServer(){}
    private:
    int _sock;//套接字
    uint16_t _port;//端口号
    func_t _func;//处理函数
    };
}